﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;

using Service.Models;

namespace Service
{
    public class CA1TableClient
    {
        private String dataConnectionString = "UseDevelopmentStorage=true";

        // Real storage account
        //private String dataConnectionString = "DefaultEndpointsProtocol = https; AccountName = gfinnx00115840; AccountKey = a21rM / Lh5n2Niozy / VKAh85JBJgePp9weCWtvrf3MhF90 + Eeu2RMC5yuOCz2o4bvXuyLdwsVlcKH1WU73Tvi8A ==";

        private String tableName = "gfinnx00115840";        // Setting to the same as storage account might fix 
        private CloudStorageAccount account;
        private CloudTableClient tableClient;
        private CloudTable table;
        private TableQuery<StockDetails> query = new TableQuery<StockDetails>();

        /// <summary>
        /// 
        ///     Pre     :- Default constructor for client table class
        ///
        ///     Post    :- The table is created and initialized when this is complete
        ///     
        /// </summary>
        public CA1TableClient()
        {
            try
            {
                // get account details for connection string
                account = CloudStorageAccount.Parse(dataConnectionString);

                // create the table client handle
                tableClient = account.CreateCloudTableClient();

                // create the table if it doesn't exist
                table = tableClient.GetTableReference(tableName);
                if (table.Exists() == false)
                {
                    table.CreateIfNotExists();
                    // Populate the table with some basic data 
                    insertBasicData();
                }
            }
            catch ( Exception e )
            {
                Console.WriteLine(e.ToString());
            }
        }
        /// <summary>
        /// 
        ///     Pre     :- The database connection must be open
        ///
        ///     Post    :- returns the table with some basic data inserted
        ///     
        /// </summary>
        private void insertBasicData()
        {
            // insert 4 entities
            TableOperation insertOperation = TableOperation.Insert(
                                    new StockDetails 
                                    { 
                                        ProductIdSymbol  = "X00001", 
                                        ProductNameSymbol = "Milk",
                                        PurchacePrice = 0.99,
                                        SalesPrice = 1.21,
                                        CurrentStockLevel = 58,
                                        StartingStockLevel = 100
                                    }
                                    );
            insertOperation = TableOperation.Insert(
                                    new StockDetails
                                    {
                                        ProductIdSymbol = "X00002",
                                        ProductNameSymbol = "Coffee",
                                        PurchacePrice = 3.00,
                                        SalesPrice = 4.99,
                                        CurrentStockLevel = 8,
                                        StartingStockLevel = 10
                                    }
                                    );
            insertOperation = TableOperation.Insert(
                                    new StockDetails
                                    {
                                        ProductIdSymbol = "X00003",
                                        ProductNameSymbol = "Vodka",
                                        PurchacePrice = 13.29,
                                        SalesPrice = 18.99,
                                        CurrentStockLevel = 21,
                                        StartingStockLevel = 50
                                    }
                                    );
            insertOperation = TableOperation.Insert(
                                    new StockDetails
                                    {
                                        ProductIdSymbol = "X00004",
                                        ProductNameSymbol = "Guinness",
                                        PurchacePrice = 0.99,
                                        SalesPrice = 1.55,
                                        CurrentStockLevel = 0,
                                        StartingStockLevel = 10
                                    }
                                    );
            table.Execute(insertOperation);
        }
        /// <summary>
        /// 
        ///     Pre     :- The database connection must be open
        ///
        ///     Post    :- returns all the elements in the database
        ///     
        /// </summary>
        public IEnumerable<StockDetails> GetAllListings()
        {
            TableQuery<StockDetails> query = new TableQuery<StockDetails>();        // Get all
            List<StockDetails> ret = new List<StockDetails>();

            foreach (var entity in table.ExecuteQuery(query))
            {
                if (ret == null)
                {
                    ret.Add(entity);
                }
                else
                {
                    //
                    // Dont put the data in twice using the prod id 
                    //
                    bool cont = false;
                    foreach(StockDetails tmp in ret)
                    {
                        if (tmp.ProductIdSymbol == entity.ProductIdSymbol)
                            cont = true;
                    }
                    if (cont == false)
                    {
                        ret.Add(entity);
                    }
                }
            }
            return ret;
        }
        /// <summary>
        /// 
        ///     Pre     :- The database connection must be open
        ///                and the idinput value must be contained
        ///
        ///     Post    :- returns a single element from the database
        ///                or null if the element isnt present
        ///     
        /// </summary>
        public StockDetails GetSingleItem(String idInput)
        {
            return FindItem(idInput);
        }
        /// <summary>
        /// 
        ///     Pre     :- The database connection must be open
        ///                and the idinput value must be contained
        ///
        ///     Post    :- returns true if the database has been altered
        ///     
        /// </summary>
        public bool DeleteListing(String idInput)
        {
            StockDetails temp = FindItem(idInput);
            if ( temp != null)
            {
                TableOperation deleteOperation = TableOperation.Delete(temp);
                table.Execute(deleteOperation);
                return true;
            }
            return false;
        }
        /// <summary>
        /// 
        ///     Pre     :- The database connection must be open
        ///                and the input value is the roe key value
        ///                for the new element to be added
        ///
        ///     Post    :- returns the status code returned from the operation
        ///     
        /// </summary>
        public int AddListing(StockDetails input)
        {
            TableOperation insertOrReplaceOperation;
            if (FindItem(input.ProductIdSymbol) == null)
            {
                insertOrReplaceOperation = TableOperation.Insert(input);
            }
            else
            {
                // This might not be seen as valid based on your view of an add operation
                //
                insertOrReplaceOperation = TableOperation.Replace(input);
            }
            // Execute the operation and return the http status code from it
            //
            return table.Execute(insertOrReplaceOperation).HttpStatusCode;
        }
        /// <summary>
        /// 
        ///     Pre     :- The database connection must be open
        ///                and the input value must be contained
        ///
        ///     Post    :- returns true if the database has been altered
        ///     
        /// </summary>
        public bool UpdateListing(StockDetails input)
        {
            StockDetails temp = FindItem(input.ProductIdSymbol);

            if (temp == null)
            {
                return false;
            }
            else
            {
                TableOperation updateOperation = TableOperation.Merge(input);
                table.Execute(updateOperation);
                return true;
            }
        }
        /// <summary>
        /// 
        ///     Pre     :- The database connection must be open
        ///                and the idinput value must be contained
        ///
        ///     Post    :- returns true if the database has been altered
        ///     
        /// </summary>
        public bool UpdateListing(String idInput, StockDetails input)
        {
            StockDetails temp1 = FindItem(idInput);
            StockDetails temp2 = FindItem(input.ProductIdSymbol);

            if (temp1 == null && temp2 == null)
            {
                return false;
            }
            else if (temp1 == null && temp2 != null )
            {
                AddListing(temp1);
                temp2.ProductIdSymbol = idInput;
                UpdateListing(temp2);
                DeleteListing(input.ProductIdSymbol);
                return true;
            }
            else if (temp1 != null && temp2 == null)
            {
                AddListing(temp2);
                DeleteListing(idInput);
                return true;
            }
            else
            {
                temp2.ProductIdSymbol = idInput;
                UpdateListing(temp2);
                DeleteListing(input.ProductIdSymbol);
                return true;
            }
        }
        /// <summary>
        /// 
        ///     Pre     :- The database connection must be open
        ///                and the input value must be contained
        ///
        ///     Post    :- returns true if the database contains 
        ///                a matching element
        ///     
        /// </summary>
        private StockDetails FindItem(String input)
        {
            TableQuery<StockDetails> query = new TableQuery<StockDetails>().Where(
                                                                        TableQuery.GenerateFilterCondition
                                                                        (
                                                                            "ProductIdSymbol",
                                                                            QueryComparisons.Equal,
                                                                            input
                                                                        )
                                                                      );
            // Returns the first and should be the only matching element
            foreach (var entity in table.ExecuteQuery(query))
                return (StockDetails)entity;    

            return null;    // not found return null
        }
    }
}